#include <stdio.h>
#include <string.h>
#include "tools.h"

#define NIVEAUX 5
#define TAILLE 32
char PILE[NIVEAUX][TAILLE];
char scratch[TAILLE];
int pointeur_pile;

char ep[TAILLE]; // Entree Pile
int long_entree_pile;

int entree_pile(void);
int commandes_speciales(void);
int push(void);
int pop(void);

#define SCRATCH 32

int main(void)
{
  int i;
  unsigned long adresse_mem;
  char scratch[SCRATCH];

  for(i=0; i < TAILLE; i++)
	  PILE[TAILLE-1][i] = 127;
  PILE[0][1] = 128;

   pointeur_pile = NIVEAUX;
   while(1)
   {
	  if (  entree_pile() == 0 )
	  {
		  // SD Stack Dump
		  if ( (ep[0]=='S') && (ep[1]=='D') )
		  {
			  for(i=NIVEAUX-1; i >=0; i--)
			   printf("N%d=[%s]\n",i , PILE[i]);
			  printf("SP=%d\n", pointeur_pile);
		  }
		  // DROP
		  else if ( (ep[0]=='D') && (ep[1]=='R')  && (ep[2]=='O') && (ep[3]=='P'))
		  {
			  pointeur_pile++;
			  if ( pointeur_pile > NIVEAUX )
			  {
				  printf("STACK UNDERFLOW !\n");
				  pointeur_pile = NIVEAUX;
			  }
			  else
			     PILE[pointeur_pile-1][0] = '\0'; // RAZ du niveau droppe
		  }
		  // DUP
		  else if ( (ep[0]=='D') && (ep[1]=='U')  && (ep[2]=='P') )
		  {
					pointeur_pile--;
					if ( pointeur_pile < 0)
					{
						pointeur_pile = 0;
						printf("STACK OVERFLOW !\n");
					}
					else if ( pointeur_pile == NIVEAUX-1 )
					{
						pointeur_pile = NIVEAUX;
						printf("TOO FEW ARGUMENTS !\n");
					}
					else
					{
						//printf("DUP de %s\n", PILE[pointeur_pile+1] );
						strcpy(PILE[pointeur_pile], PILE[pointeur_pile+1]);
					}
		  }
		  // SWAP
		  else if ( (ep[0]=='S') && (ep[1]=='W')  && (ep[2]=='A') && (ep[3]=='P')  )
		  {
				// minimum 2 niveaux pour SWAP
				if ( pointeur_pile >= (NIVEAUX-1) )
				{
					printf("TOO FEW ARGUMENTS !\n");
				}
				else
				{
					strcpy(scratch, PILE[pointeur_pile]);
					strcpy(PILE[pointeur_pile], PILE[pointeur_pile+1]);
					strcpy(PILE[pointeur_pile+1], scratch);
				}
		  }


		  // PEEK
		  else if ( (ep[0]=='P') && (ep[1]=='E')  && (ep[2]=='E') && (ep[3]=='K')  )
		  {
				        // prend l'addresse sur la pile
						if ( pointeur_pile == NIVEAUX )
						{
							printf("TOO FEW ARGUMENTS !\n");
						}
						else
						{
							adresse_mem = fast_hexstr2int(PILE[pointeur_pile]);
							//memcpy(car, (char*)(6300000), sizeof(car));
							printf("PEEK ADDRESS: %s, contenu=%lu\n", PILE[pointeur_pile], *(unsigned long*)adresse_mem);
						}
		  }
		  // POKE
		  else if ( (ep[0]=='P') && (ep[1]=='O')  && (ep[2]=='K') && (ep[3]=='E')  )
		  {
				        // prend l'addresse sur la pile et la valeur
						if ( pointeur_pile == NIVEAUX-1 )
						{
							printf("TOO FEW ARGUMENTS !\n");
						}
						else
						{
							printf("POKE ADDRESS: %s, VALUE %s\n", PILE[pointeur_pile+1], PILE[pointeur_pile]);
							adresse_mem = fast_hexstr2int(PILE[pointeur_pile+1]);
							//*(adresse_mem) = 201;
						}
		  }


		  // STOP Stack Top
		  else if ( (ep[0]=='S') && (ep[1]=='T')  && (ep[2]=='O') && (ep[3]=='P')  )
		  {
					printf("STACK TOP = %p\n", &PILE[pointeur_pile]);
					fast_memaddress2hexstr(&PILE[pointeur_pile], scratch);
					strcpy(ep, scratch);
					push();
		  }
		  // SEND Stack End
		  else if ( (ep[0]=='S') && (ep[1]=='E')  && (ep[2]=='N') && (ep[3]=='D')  )
		  {
					printf("STACK END = %p\n", &PILE[NIVEAUX]);
					fast_memaddress2hexstr(&PILE[NIVEAUX], scratch);
					strcpy(ep, scratch);
					push();
		  }


/* PUSH */else // Pas une commande -> empile l'entree
			 push();
	  }
	  else
	  {
		  //printf("NO PUSH !\n");
	  }
   }

	return 0;
}

int push()
{
	pointeur_pile--;
	if ( pointeur_pile < 0)
	{
		pointeur_pile = 0;
		printf("STACK OVERFLOW !\n");
	}
	else
	{
	  strcpy(PILE[pointeur_pile], ep);
	}
	//printf("SP=%d\n", pointeur_pile);
	return 0;
}

int pop()
{

	 return 0;
}

int commandes_speciales()
{
	return 0;
}

int entree_pile(void)
{
	char ch;
	long_entree_pile = 0;
	printf(">");
	while( (ch = getchar()) != '\n' )
	{
		ep[long_entree_pile++] = ch;
		if ( long_entree_pile >= TAILLE-1 )
		{
			printf("Trop long !\n");
			ep[0] = '\0';
			while( ((ch = getchar()) != '\n') && (ch != EOF) ); // FLUSH
			return -1;
		}
	}
	ep[long_entree_pile] = '\0';
	//printf("ENTREE=[%s]\n", niveau_zero);
  return 0;
}
